using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using System.Configuration;
using ShopPowerTemplate.Services;
using ShopPowerTemplate.IoC.Resources;
using ShopPowerTemplate.Entities;

namespace ShopPowerTemplate.IoC.Unity
{
    internal class IoCUnityContainerBase
    {
        #region Members

        IDictionary<string, IUnityContainer> _ContainersDictionary;

        #endregion

        #region Constructor

        public IoCUnityContainerBase()
        {
            _ContainersDictionary = new Dictionary<string, IUnityContainer>();

                //Create root container
            IUnityContainer rootContainer = new UnityContainer();
            _ContainersDictionary.Add("RootContext", rootContainer);

                //Create container for real context, child of root container
            IUnityContainer realAppContainer = rootContainer.CreateChildContainer();
            _ContainersDictionary.Add("RealAppContext", realAppContainer);

                //Create container for testing, child of root container
            IUnityContainer fakeAppContainer = rootContainer.CreateChildContainer();
            _ContainersDictionary.Add("FakeAppContext", fakeAppContainer);
           
            ConfigureRootContainer(rootContainer);
            ConfigureRealContainer(realAppContainer);
            ConfigureFakeContainer(fakeAppContainer);
        }

        #endregion

        #region Private Methods
        
        protected virtual void ConfigureRootContainer(IUnityContainer container)
        {            
            container.RegisterType<IAddressService, AddressService>(new TransientLifetimeManager());
            container.RegisterType<IAppSettingsService, AppSettingsService>(new TransientLifetimeManager());
            container.RegisterType<ICategoryService, CategoryService>(new TransientLifetimeManager());
            container.RegisterType<ICustomerService, CustomerService>(new TransientLifetimeManager());
            container.RegisterType<IImageService, ImageService>(new TransientLifetimeManager());
            container.RegisterType<IOptionService, OptionService>(new TransientLifetimeManager());
            container.RegisterType<IOptionTypeService, OptionTypeService>(new TransientLifetimeManager());
            container.RegisterType<IOrderService, OrderService>(new TransientLifetimeManager());
            container.RegisterType<IOrderDetailService, OrderDetailService>(new TransientLifetimeManager());
            container.RegisterType<IOrderStateService, OrderStateService>(new TransientLifetimeManager());
            container.RegisterType<IProductService, ProductService>(new TransientLifetimeManager());
            container.RegisterType<IProductDetailService, ProductDetailService>(new TransientLifetimeManager());
            container.RegisterType<IReviewService, ReviewService>(new TransientLifetimeManager());
            container.RegisterType<IShippingCostService, ShippingCostService>(new TransientLifetimeManager());
            container.RegisterType<ISubcategoryService, SubcategoryService>(new TransientLifetimeManager());
            container.RegisterType<IUserService, UserService>(new TransientLifetimeManager());
        }
        
        protected virtual void ConfigureRealContainer(IUnityContainer container)
        {
			container.RegisterType<IEntitiesDB, EntitiesDB>(new PerExecutionContextLifetimeManager());
        }

        protected virtual void ConfigureFakeContainer(IUnityContainer container)
        {            
			container.RegisterType<IEntitiesDB, EntitiesDB>(new PerExecutionContextLifetimeManager());
        }

        #endregion

        #region IServiceFactory Members
        
        public virtual TService Resolve<TService>()
        {            
            string containerName = ConfigurationManager.AppSettings["defaultIoCContainer"];

            if (String.IsNullOrEmpty(containerName)
                ||
                String.IsNullOrWhiteSpace(containerName))
            {
                throw new ArgumentNullException(Messages.exception_DefaultIOCSettings);
            }

            if (!_ContainersDictionary.ContainsKey(containerName))
                throw new InvalidOperationException(Messages.exception_ContainerNotFound);

            IUnityContainer container = _ContainersDictionary[containerName];

            return container.Resolve<TService>();
        }
        
        public virtual object Resolve(Type type)
        {            
            string containerName = ConfigurationManager.AppSettings["defaultIoCContainer"];

            if (String.IsNullOrEmpty(containerName)
                ||
                String.IsNullOrWhiteSpace(containerName))
            {
                throw new ArgumentNullException(Messages.exception_DefaultIOCSettings);
            }

            if (!_ContainersDictionary.ContainsKey(containerName))
                throw new InvalidOperationException(Messages.exception_ContainerNotFound);

            IUnityContainer container = _ContainersDictionary[containerName];

            return container.Resolve(type, null);
        }
        
        public virtual void RegisterType(Type type)
        {
            IUnityContainer container = this._ContainersDictionary["RootContext"];

            if (container != null)
                container.RegisterType(type, new TransientLifetimeManager());
        }

        #endregion
    }
}
